/*
 * Copyright 2007-2008  Lukasz Laszko lukaszlaszko@gmail.com
 * 
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for any purpose and without fee is hereby
 * granted, provided that the above copyright notice appear in all
 * copies and that both that the copyright notice and this
 * permission notice and warranty disclaimer appear in supporting
 * documentation, and that the name of the author not be used in
 * advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 * 
 * The author disclaim all warranties with regard to this
 * software, including all implied warranties of merchantability
 * and fitness.  In no event shall the author be liable for any
 * special, indirect or consequential damages or any damages
 * whatsoever resulting from loss of use, data or profits, whether
 * in an action of contract, negligence or other tortious action,
 * arising out of or in connection with the use or performance of
 * this software. 
 */
package org.pg.biomedics.asr.runtime;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import java.util.Enumeration;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Logger;

import org.mortbay.jetty.Server;
import org.mortbay.xml.XmlConfiguration;
import org.xml.sax.SAXException;

import org.pg.biomedics.asr.concurrent.TaskScheduler;
import org.pg.biomedics.asr.service.ServicesPool;
import org.pg.biomedics.asr.config.ConfigurationManager;

/**
 * Main runtime class. Does runtime initialization and deinitialization
 * @author Lukasz Laszko
 */
public class Runtime 
{
    // <editor-fold desc="Constants">
    
    private static final String RUNTIME_PROPERTIES_LOCATION = "." + File.separator + "etc" + File.separator + "runtime.properties";    
    
    // </editor-fold>
    
    // <editor-fold desc="Fields">
    
    private Logger logger = Logger.getLogger(Runtime.class);
    private ConfigurationManager configuration;
    private Thread taskSchedulerThread;
    private Thread webServicesThread;    
    
    // </editor-fold>
    
    // <editor-fold desc="Static methods">
    
    public static void main(String[] args)
    {
        // initialize initially logging
        BasicConfigurator.configure();
        
        // run application
        new Runtime().run();
        System.exit(0);
    }
    
    // </editor-fold>
    
    // <editor-fold desc="Public methods">
    
    /**
     * Conatins logic for web server and JAX-WS with WSIT based web services 
     * initialization. Scheduler is started too.
     */
    public void run()
    {
        try
        {
            // initialize components
            this.logger.info("Loading custom runtime properties from " + RUNTIME_PROPERTIES_LOCATION);            
            initializeRuntime();
            this.logger.info("Custom runtime properties load succeeded");
            
            this.logger.info("Initializaing log4j");            
            initializeLogging();
            this.logger.info("Log4j initilization succeeded");
                        
            this.logger.info("Initializing services pool");            
            InitializeServicesPool();
            this.logger.info("Services pool initialization succeeded");
            
            this.logger.info("Initializing task scheduler");            
            initializeScheduler();
            this.logger.info("Task scheduler initialization succeeded");                       
            
            this.logger.info("Initializing web services");
            initializeWebServices();
            this.logger.info("Web services initialization failed");
            
            // all initilized wait for user to stop
            logger.info("All services started");
            System.out.println("Press ENTER to stop services...");
            System.in.read();
            
            // close components
            this.logger.info("Stopping web services");
            shutdownWebServices();
            this.logger.info("Web services stopped");
            
            this.logger.info("Stopping task scheduler");
            shutdownWebServices();
            this.logger.info("Task scheduler stopped");
        }
        catch (Throwable th)
        {
            this.logger.error("Startup error has occured", th);
        }
    }
    
    // </editor-fold>
    
    // <editor-fold desc="Support methods">
    
    /**
     * Makes runtime initiaization. Provides logic for runtime configuration load from
     * well-known location
     * @throws Exception
     */
    private void initializeRuntime() throws Exception
    {
        this.configuration = new ConfigurationManager();
        this.configuration.configure(RUNTIME_PROPERTIES_LOCATION);
    }
    
    /**
     * Initializes Log4j from system properties custom configuration
     */
    private void initializeLogging()
    {
        PropertyConfigurator.configure(System.getProperties());        
    }
    
        /**
     * Provides services pool initialization
     */
    private void InitializeServicesPool() throws Exception
    {
        ServicesPool.getInstance().configure(false);
    }
    
        
    /**
     * Starts task scheduler
     */
    private void initializeScheduler() throws Exception
    {
        if (this.configuration.isSchedulerEnabled())
        {        
            // start scheduler
            final TaskScheduler scheduler = new TaskScheduler();
            scheduler.initialize();
            
            ServicesPool.getInstance().setTaskScheduler(scheduler);

            this.taskSchedulerThread = new Thread()
            {
                @Override
                public void run()
                {                                                  
                    scheduler.run();
                    scheduler.shutdown();                        
                }
            };
            this.taskSchedulerThread.start();     
        }
    }
   
    /**
     * Starts Jetty web server and provides JAX-WS initialization
     */
    private void initializeWebServices() throws Exception 
    {
        if (this.configuration.isWebServiceEnabled())
        {
            this.webServicesThread = new Thread() 
            {
                @Override
                public void run()
                {
                    try
                    {
                        Server server = new Server();

                        String configLocation = configuration.getWebServerConfig();
                        XmlConfiguration xmlConfiguration = new XmlConfiguration(new FileInputStream(configLocation));
                        xmlConfiguration.configure(server);

                        server.start();
                        server.join();
                    }
                    catch (Exception ex)
                    {
                        logger.error("webServices start failed", ex);
                    }
                }
            };

            this.webServicesThread.start();
        }
    }
    
    /**
     * Close scheduler
     */
    private void shutdownScheduler()
    {
        if (this.taskSchedulerThread != null)
        {
            this.taskSchedulerThread.interrupt();
            this.taskSchedulerThread = null;
        }
    }
    
    /**
     * Stops jetty and web services
     */
    private void shutdownWebServices()
    {
        if (this.webServicesThread != null)
        {
            this.webServicesThread.interrupt();
            this.webServicesThread = null;
        }
    }       
    
    // </editor-fold>
}
